import http
import json
import traceback
from decimal import Decimal

from django.db import transaction
from django.http import JsonResponse, HttpResponseBadRequest
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection
from redis import Redis

from apps.areas.models import Address
from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from utils.views import LoginRequiredJSONMixin

class OrderSettlementView(LoginRequiredJSONMixin, View):
    """结算订单"""

    def get(self, request):
        """提供订单结算页面"""
        # 获取登录用户
        user = request.user
        # 从redis里取出skuid
        redis_conn: Redis = get_redis_connection('carts')
        # 获取hash的数据
        redis_carts = redis_conn.hgetall('carts_%s' % user.id)
        # 获取set里的数据
        carts_selected = redis_conn.smembers('selected_%s' % user.id)
        # 把redis取出的数据 重新 放到一个新的字典里 包括他的数量
        cart_data = {}
        for sku_id in carts_selected:
            cart_data[int(sku_id)] = int(redis_carts[sku_id])

        skus = SKU.objects.filter(id__in=cart_data.keys())

        sku_list = []
        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'default_image_url': sku.default_image.url,  # 图片
                'name': sku.name,  # 名字
                'price': sku.price,  #
                'count': cart_data[sku.id],  # 数量
            })
        print('sku_list',sku_list)
        # 运费 这里固定位10元
        freight = Decimal('10.00')  # 运费
        # 获取所有的用户的地址信息
        addrs = Address.objects.filter(user=user, is_deleted=False)
        addrs_list = []
        for addr in addrs:
            addrs_list.append({
                'province': addr.province.name,
                'city': addr.city.name,
                'district': addr.district.name,
                'place': addr.place,
                'receiver': addr.receiver,
                'mobile': addr.mobile,
                'id': addr.id,

            })
        # 拼接json返回

        context = {
            'skus': sku_list,
            'freight': freight,
            'addresses': addrs_list,
            'default_address_id': request.user.default_address,
        }

        return JsonResponse({"context": context, 'code': 0, 'errmsg': 'ok'})


# 订单提交
class OrderCommitView(LoginRequiredJSONMixin, View):
    """订单提交"""

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 获取当前要保存的订单数据
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')
        # 校验参数
        if not all([address_id, pay_method]):
            return HttpResponseBadRequest('缺少必传参数')
        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return HttpResponseBadRequest('参数address_id错误')
        # 判断pay_method是否合法
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return HttpResponseBadRequest('参数pay_method错误')

        # 获取登录用户
        user = request.user
        # 生成订单编号：年月日时分秒+用户编号
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)

        # 显式的开启一个事务
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()

            # 暴力回滚
            try:
                # 保存订单基本信息
                order=OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0, #商品数量
                    # total_amount=Decimal('0'), #商品总金额
                    total_amount=0, #商品总金额
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']

                )

                # 从redis读取购物车中被勾选的商品信息
                redis_conn: Redis = get_redis_connection('carts')
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                selected = redis_conn.smembers('selected_%s' % user.id)
                carts = {}
                for sku_id in selected:
                    carts[int(sku_id)] = int(redis_cart[sku_id])
                # 遍历所有的商品id
                sku_ids = carts.keys()
                # 遍历购物车中被勾选的商品信息
                for sku_id in sku_ids:
                    while True:
                        # 查询每一个商品的SKU数据
                        sku = SKU.objects.get(id=sku_id)

                        # 读取原始库存
                        origin_stock = sku.stock
                        origin_sales = sku.sales

                        # 获取当前这件商品的购买数量
                        sku_count = carts[sku.id]
                        # 判断数量和库存
                        if sku_count > sku.stock:
                            # 出错就回滚
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({'code': 400, 'errmsg': '库存不足'})

                        # import time
                        # time.sleep(5)
                        # 商品的库存减少
                        # sku.stock -= sku_count
                        # 商品的销量累加
                        # sku.sales += sku_count
                        # sku.save()
                        # 乐观锁更新库存和销量
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        # 如果下单失败，但是库存足够时，继续下单，直到下单成功或者库存不足为止
                        if result == 0:
                            continue

                        # 生成订单商品对象 OrderGoods（多）
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price,
                        )
                        # 保存商品订单中总价和总数量
                        order.total_count += sku_count
                        order.total_amount += (sku_count * sku.price)

                        # 下单成功或者失败就跳出循环
                        break

                # 添加邮费和保存订单信息
                order.total_amount+=order.freight
                order.save()

            except Exception as e:
                traceback.print_exc() # 会打印原始红色的异常数据
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': 400, 'errmsg': '下单失败'})

            # 提交订单成功，显式的提交一次事务
            transaction.savepoint_commit(save_id)

        # 清除购物车中已结算的商品(*是拆包) 注意：只删除选中的
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id, *selected)
        pl.srem('selected_%s' % user.id, *selected)
        pl.execute()

        # 响应提交订单结果
        return JsonResponse({'code': 0, 'errmsg': '下单成功', 'order_id': order.order_id})
